
#include "NewBoost.Feature.h"

using namespace new_boost;

// [*] CFeatureExtractor

void new_boost::CFeatureExtractor::InitSPL_HOG()
{
	CShapePattern_SingleCellInBlock tCell;

	CSimpleTypeArray<CShapePattern_SingleCellInBlock> CellList_2x2;
	CellList_2x2.Clear();
	tCell.RatioBox.myInit(0.0, 0.0, 0.5, 0.5); tCell.Weight = +1.0; CellList_2x2.PushBack(tCell);
	tCell.RatioBox.myInit(0.5, 0.0, 0.5, 0.5); tCell.Weight = +1.0; CellList_2x2.PushBack(tCell);
	tCell.RatioBox.myInit(0.0, 0.5, 0.5, 0.5); tCell.Weight = +1.0; CellList_2x2.PushBack(tCell);
	tCell.RatioBox.myInit(0.5, 0.5, 0.5, 0.5); tCell.Weight = +1.0; CellList_2x2.PushBack(tCell);

	SPL_HOG.Clear();
	double ww, wh, bw, bh, bx, by;
	ww = SPL_HOG_Win_W; wh = SPL_HOG_Win_H;
	bw = SPL_HOG_Blk_BaseW; bh = SPL_HOG_Blk_BaseH;
	bx = SPL_HOG_Blk_BaseStrideX; by = SPL_HOG_Blk_BaseStrideY;

	for ( ; ; )
	{
		if (bw>ww || bh>wh) break;

		CShapePatternList::GenBlockPattern(SPL_HOG, true, 0.0, 0.0, ww, wh, bw, bh, bx, by, CellList_2x2);

		bw *= SPL_HOG_Blk_ScalingFactor;
		bh *= SPL_HOG_Blk_ScalingFactor;
		bx *= SPL_HOG_Blk_ScalingFactor;
		by *= SPL_HOG_Blk_ScalingFactor;
	}
}

void new_boost::CFeatureExtractor::InitShapePatternLists()
{
	InitSPL_HOG();
}

void new_boost::CFeatureExtractor::InitIFB()
{
	IFB_Prototype.myInit();

	CImageFilter_RGB* pFilter_RGB = IFB_Prototype.pBasicFilter_RGB;

	CImageFilter_Lab* pFilter_Lab = new CImageFilter_Lab();
	pFilter_Lab->PushBackInputResponse(pFilter_RGB, 0);
	pFilter_Lab->PushBackInputResponse(pFilter_RGB, 1);
	pFilter_Lab->PushBackInputResponse(pFilter_RGB, 2);
	IFB_Prototype.PushBackFilter(pFilter_Lab);

	CImageFilter_Gaussian* pFilter_Gaussian_R = new CImageFilter_Gaussian(IFB_TextonSigma * 1.0);
	CImageFilter_Gaussian* pFilter_Gaussian_G = new CImageFilter_Gaussian(IFB_TextonSigma * 1.0);
	CImageFilter_Gaussian* pFilter_Gaussian_B = new CImageFilter_Gaussian(IFB_TextonSigma * 1.0);
	CImageFilter_Gaussian* pFilter_Gaussian_L = new CImageFilter_Gaussian(IFB_TextonSigma * 1.0);
	CImageFilter_Gaussian* pFilter_Gaussian_a = new CImageFilter_Gaussian(IFB_TextonSigma * 1.0);
	CImageFilter_Gaussian* pFilter_Gaussian_b = new CImageFilter_Gaussian(IFB_TextonSigma * 1.0);
	pFilter_Gaussian_R->PushBackInputResponse(pFilter_RGB, 0);
	pFilter_Gaussian_G->PushBackInputResponse(pFilter_RGB, 1);
	pFilter_Gaussian_B->PushBackInputResponse(pFilter_RGB, 2);
	pFilter_Gaussian_L->PushBackInputResponse(pFilter_Lab, 0);
	pFilter_Gaussian_a->PushBackInputResponse(pFilter_Lab, 1);
	pFilter_Gaussian_b->PushBackInputResponse(pFilter_Lab, 2);
	IFB_Prototype.PushBackFilter(pFilter_Gaussian_R);
	IFB_Prototype.PushBackFilter(pFilter_Gaussian_G);
	IFB_Prototype.PushBackFilter(pFilter_Gaussian_B);
	IFB_Prototype.PushBackFilter(pFilter_Gaussian_L);
	IFB_Prototype.PushBackFilter(pFilter_Gaussian_a);
	IFB_Prototype.PushBackFilter(pFilter_Gaussian_b);

	CImageFilter_Gradient* pFilter_Gradient = new CImageFilter_Gradient(0.0, false);
	pFilter_Gradient->PushBackInputResponse(pFilter_Gaussian_L, 0);
	IFB_Prototype.PushBackFilter(pFilter_Gradient);

	CImageFilter_2D_Histogram* pFilter_2D_Histogram = 
		new CImageFilter_2D_Histogram(0, 1, 9, -PI/2, +PI/2, CImageFilter_2D_Histogram::MODE_BOUNDING, true);
	pFilter_2D_Histogram->PushBackInputResponse(pFilter_Gradient, 0);
	pFilter_2D_Histogram->PushBackInputResponse(pFilter_Gradient, 1);
	IFB_Prototype.PushBackFilter(pFilter_2D_Histogram);

	CImageFilter_Kernel2D* pFilter_AvgHist = new CImageFilter_Kernel2D();
	pFilter_AvgHist->Ker.fType = CKernel2D<double>::TYPE_CONVOLVE;
	pFilter_AvgHist->Ker.kernelX.SetLinearInterpolation(4);
	pFilter_AvgHist->Ker.kernelY.SetLinearInterpolation(4);
	pFilter_AvgHist->PushBackInputResponse(pFilter_2D_Histogram, 0);
	pFilter_AvgHist->PushBackInputResponse(pFilter_2D_Histogram, 1);
	pFilter_AvgHist->PushBackInputResponse(pFilter_2D_Histogram, 2);
	pFilter_AvgHist->PushBackInputResponse(pFilter_2D_Histogram, 3);
	pFilter_AvgHist->PushBackInputResponse(pFilter_2D_Histogram, 4);
	pFilter_AvgHist->PushBackInputResponse(pFilter_2D_Histogram, 5);
	pFilter_AvgHist->PushBackInputResponse(pFilter_2D_Histogram, 6);
	pFilter_AvgHist->PushBackInputResponse(pFilter_2D_Histogram, 7);
	pFilter_AvgHist->PushBackInputResponse(pFilter_2D_Histogram, 8);
	IFB_Prototype.PushBackFilter(pFilter_AvgHist);

	// Setting Response Output

	pFilter_Gaussian_R->PushBackOutput(0);	// Gaussian(R)
	pFilter_Gaussian_G->PushBackOutput(0);	// Gaussian(G)
	pFilter_Gaussian_B->PushBackOutput(0);	// Gaussian(B)
	pFilter_Gaussian_L->PushBackOutput(0);	// Gaussian(L)
	pFilter_Gaussian_a->PushBackOutput(0);	// Gaussian(a)
	pFilter_Gaussian_b->PushBackOutput(0);	// Gaussian(b)

	pFilter_AvgHist->PushBackOutput(0);		// Gradient Histogram
	pFilter_AvgHist->PushBackOutput(1);
	pFilter_AvgHist->PushBackOutput(2);
	pFilter_AvgHist->PushBackOutput(3);
	pFilter_AvgHist->PushBackOutput(4);
	pFilter_AvgHist->PushBackOutput(5);
	pFilter_AvgHist->PushBackOutput(6);
	pFilter_AvgHist->PushBackOutput(7);
	pFilter_AvgHist->PushBackOutput(8);

	IFB_Prototype.GetOutputDimension(true);

	IFB_Prototype.SetCachePath("");
}

CImagePositionFeatureExtractor* new_boost::CFeatureExtractor::GetIPFE()
{
	CSimpleTypeArray<int> NI;
	int iStart, iAmount, i;

	//InitIFB();
	//InitShapePatternLists();

	int FilterResponseDimension = IFB_Prototype.GetOutputDimension();

	C_IPFC_ImageFilterBankOwner* pIFBO = new C_IPFC_ImageFilterBankOwner(IFB_Prototype.myClone(), IFB_ImageExtent, false);

	iStart = 6; iAmount = 9; NI.Clear(); for ( i = iStart; i < iStart + iAmount; ++i ) NI.PushBack(i);
	pIFBO->PushBackResponseUser(new C_IPFC_ResponseUser_BlockNormalizer(iAmount, &SPL_HOG, true, new CMyNormalizer_L2_NORM(1.0), false), NI.pElement);

	CCompositeIPFC* pCompositeIPFC = new CCompositeIPFC();
	pCompositeIPFC->PushBack(pIFBO);

	return new CBasicIPFE(pCompositeIPFC);
}

CImagePyramidPositionFeatureExtractor* new_boost::CFeatureExtractor::GetIPPFE( int CacheSize )
{
	return new CImagePyramidPositionFeatureExtractor(GetIPFE(), CacheSize);
}

// [*] CWindowGradient

new_boost::CWindowGradient::CWindowGradient()
{
	pHistogramConfig = NULL;
	pIPPFE = NULL;
}

new_boost::CWindowGradient::~CWindowGradient()
{
	CDataStructureTools::MyRelease_Single(pIPPFE);
}

void new_boost::CWindowGradient::_InitIFB()
{
	IFB.myInit();

	CImageFilter_RGB* pFilter_RGB = IFB.pBasicFilter_RGB;

	CImageFilter_Lab* pFilter_Lab = new CImageFilter_Lab();
	pFilter_Lab->PushBackInputResponse(pFilter_RGB, 0);
	pFilter_Lab->PushBackInputResponse(pFilter_RGB, 1);
	pFilter_Lab->PushBackInputResponse(pFilter_RGB, 2);
	IFB.PushBackFilter(pFilter_Lab);

	CImageFilter_Gaussian* pFilter_Gaussian_R = new CImageFilter_Gaussian(IFB_TextonSigma * 1.0);
	CImageFilter_Gaussian* pFilter_Gaussian_G = new CImageFilter_Gaussian(IFB_TextonSigma * 1.0);
	CImageFilter_Gaussian* pFilter_Gaussian_B = new CImageFilter_Gaussian(IFB_TextonSigma * 1.0);
	CImageFilter_Gaussian* pFilter_Gaussian_L = new CImageFilter_Gaussian(IFB_TextonSigma * 1.0);
	CImageFilter_Gaussian* pFilter_Gaussian_a = new CImageFilter_Gaussian(IFB_TextonSigma * 1.0);
	CImageFilter_Gaussian* pFilter_Gaussian_b = new CImageFilter_Gaussian(IFB_TextonSigma * 1.0);
	pFilter_Gaussian_R->PushBackInputResponse(pFilter_RGB, 0);
	pFilter_Gaussian_G->PushBackInputResponse(pFilter_RGB, 1);
	pFilter_Gaussian_B->PushBackInputResponse(pFilter_RGB, 2);
	pFilter_Gaussian_L->PushBackInputResponse(pFilter_Lab, 0);
	pFilter_Gaussian_a->PushBackInputResponse(pFilter_Lab, 1);
	pFilter_Gaussian_b->PushBackInputResponse(pFilter_Lab, 2);
	IFB.PushBackFilter(pFilter_Gaussian_R);
	IFB.PushBackFilter(pFilter_Gaussian_G);
	IFB.PushBackFilter(pFilter_Gaussian_B);
	IFB.PushBackFilter(pFilter_Gaussian_L);
	IFB.PushBackFilter(pFilter_Gaussian_a);
	IFB.PushBackFilter(pFilter_Gaussian_b);

	CImageFilter_Gradient* pFilter_Gradient = new CImageFilter_Gradient(0.0, false);
	pFilter_Gradient->PushBackInputResponse(pFilter_Gaussian_L, 0);
	IFB.PushBackFilter(pFilter_Gradient);

	CImageFilter_2D_Histogram* pFilter_2D_Histogram = 
		new CImageFilter_2D_Histogram(0, 1, Hist_BinAmount, -PI/2, +PI/2, CImageFilter_2D_Histogram::MODE_BOUNDING, true);
	pFilter_2D_Histogram->PushBackInputResponse(pFilter_Gradient, 0);
	pFilter_2D_Histogram->PushBackInputResponse(pFilter_Gradient, 1);
	IFB.PushBackFilter(pFilter_2D_Histogram);

	this->pHistogramConfig = &pFilter_2D_Histogram->HistogramConfig;

	CImageFilter_Kernel2D* pFilter_AvgHist = new CImageFilter_Kernel2D();
	pFilter_AvgHist->Ker.fType = CKernel2D<double>::TYPE_CONVOLVE;
	pFilter_AvgHist->Ker.kernelX.SetLinearInterpolation(4);
	pFilter_AvgHist->Ker.kernelY.SetLinearInterpolation(4);
	pFilter_AvgHist->PushBackInputResponse(pFilter_2D_Histogram, 0);
	pFilter_AvgHist->PushBackInputResponse(pFilter_2D_Histogram, 1);
	pFilter_AvgHist->PushBackInputResponse(pFilter_2D_Histogram, 2);
	pFilter_AvgHist->PushBackInputResponse(pFilter_2D_Histogram, 3);
	pFilter_AvgHist->PushBackInputResponse(pFilter_2D_Histogram, 4);
	pFilter_AvgHist->PushBackInputResponse(pFilter_2D_Histogram, 5);
	pFilter_AvgHist->PushBackInputResponse(pFilter_2D_Histogram, 6);
	pFilter_AvgHist->PushBackInputResponse(pFilter_2D_Histogram, 7);
	pFilter_AvgHist->PushBackInputResponse(pFilter_2D_Histogram, 8);
	IFB.PushBackFilter(pFilter_AvgHist);

	// Setting Response Output

	int i;
	for ( i = 0; i < Hist_BinAmount; ++i )
		pFilter_2D_Histogram->PushBackOutput(i);

	IFB.GetOutputDimension(true);

	IFB.SetCachePath("");
}

void new_boost::CWindowGradient::_InitSPL()
{
	CShapePattern_SingleCellInBlock tCell;

	CSimpleTypeArray<CShapePattern_SingleCellInBlock> CellList_1x1;
	CellList_1x1.Clear();
	tCell.RatioBox.myInit(0.0, 0.0, 1.0, 1.0); tCell.Weight = +1.0; CellList_1x1.PushBack(tCell);

	SPL.Clear();
	CShapePatternList::GenBlockPattern(SPL, true, 0.0, 0.0,
		CelPix_W * WinCel_W,
		CelPix_H * WinCel_H,
		CelPix_W, CelPix_H,
		CelPix_W, CelPix_H,
		CellList_1x1);
}

void new_boost::CWindowGradient::InitIPPFE(
	double IFB_TextonSigma,
	int IFB_ImageExtent,
	int Hist_BinAmount,
	int CelPix_W,
	int CelPix_H,
	int WinCel_W,
	int WinCel_H
	)
{
	CDataStructureTools::MyRelease_Single(pIPPFE);

	this->IFB_TextonSigma = IFB_TextonSigma;
	this->IFB_ImageExtent = IFB_ImageExtent;
	this->Hist_BinAmount = Hist_BinAmount;
	_InitIFB();

	this->CelPix_W = CelPix_W;
	this->CelPix_H = CelPix_H;
	this->WinCel_W = WinCel_W;
	this->WinCel_H = WinCel_H;
	_InitSPL();

	int i;

	C_IPFC_ImageFilterBankOwner* pIFBO = new C_IPFC_ImageFilterBankOwner(IFB.myClone(), IFB_ImageExtent, false);

	for ( i = 0; i < Hist_BinAmount; ++i )
	{
		pIFBO->PushBackResponseUser(
			new C_IPFC_ResponseUser_Mean_and_Variance(C_IPFC_ResponseUser_Mean_and_Variance::MODE_MEAN_IN_CELL, &SPL),
			&i);
	}

	CCompositeIPFC* pCompositeIPFC = new CCompositeIPFC();
	pCompositeIPFC->PushBack(pIFBO);

	pIPPFE = new CImagePyramidPositionFeatureExtractor(
		new CBasicIPFE(pCompositeIPFC),
		1);

	FeatureDimension = pIPPFE->GetFeatureDimension();
}

void new_boost::CWindowGradient::InitDataSet(
	CSimpleTypeArray<CBicExampleParentFileNameSet>* pList_BicExampleParentFileNameSet,
	string strFN_BicExampleList, bool fIsTextFileMode
	)
{
	RealDataSet.InitBicExampleParentFileNameSetList(pList_BicExampleParentFileNameSet, "");
	if (fIsTextFileMode)
		RealDataSet.InitBicExampleList(strFN_BicExampleList);
	else
		RealDataSet.InitBicExampleList_Binary(strFN_BicExampleList);
	RealDataSet.InitIPPFE(this->pIPPFE, false);
	//bcDataSet.SetRealDataSet(&RealDataSet);
	//bcDataSet.SetTargetLabel(+1);
	//bcExampleList.myInit(&bcDataSet);
}

double new_boost::CWindowGradient::GetValue( int NodeIndex, int WinCel_X, int WinCel_Y, int BinIndex )
{
	int fi = WinCel_Y + WinCel_H * (WinCel_X + WinCel_W * BinIndex);
	return RealDataSet.GetExampleFeature(NodeIndex, fi);
}

void new_boost::CWindowGradient::MakeGradientVector(double* pDstData, int NodeIndex, double Weight)
{
	int i_feature, i_bin;
	int ix, iy;

	i_feature = 0;
	for ( iy = 0; iy < WinCel_H; ++iy ) for ( ix = 0; ix < WinCel_W; ++ix ) for ( i_bin = 0; i_bin < Hist_BinAmount; ++i_bin )
	{
		pDstData[i_feature] += this->GetValue(NodeIndex, ix, iy, i_bin) * Weight;
		++i_feature;
	}
}

void new_boost::CWindowGradient::MakeGradientVector(double* pDstData, const CWeightedClassificationExample& Example)
{
	MakeGradientVector(pDstData, Example.ExampleIndex, Example.Weight);
}

void new_boost::CWindowGradient::AverageGradient(double* pDstData, const CWeightedClassificationExampleList& ExampleList)
{
	double sw;
	int i_example;
	int rei;
	double tw;
	char strTemp[10001];

	//for ( i_feature = 0; i_feature < FeatureDimension; ++i_feature )
	//	pDstData[i_feature] = 0.0;

	sw = 0.0;
	for ( i_example = 0; i_example < ExampleList.ExampleAmount; ++i_example )
	{
		rei = ExampleList.rgExample[i_example].ExampleIndex;
		tw = ExampleList.rgExample[i_example].Weight;
		sw += tw;
		MakeGradientVector(pDstData, rei, tw);
		if (CMyRandom::NextInt(ExampleList.ExampleAmount/1000) == 0)
		{
			sprintf_s(strTemp, "Averaging Gradient [%.2lf%%];", 100.0*(i_example+1)/ExampleList.ExampleAmount);
			CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, false);
		}
	}

	//if (sw < MINIMUM_DOUBLE_EPS_C) sw = 1.0;
	//for ( i_feature = 0; i_feature < FeatureDimension; ++i_feature )
	//	pDstData[i_feature] /= sw;

	sprintf_s(strTemp, "Averaged Gradient [%d];", ExampleList.ExampleAmount);
	CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
}

void new_boost::CWindowGradient::AverageGradient(CSimpleTypeArray<double>& DstDataList, const CWeightedClassificationExampleList& ExampleList)
{
	DstDataList.Resize(FeatureDimension);
	DstDataList.Fill(0.0);
	AverageGradient(DstDataList.pElement, ExampleList);
}

void new_boost::CWindowGradient::_DrawCell(
	CImg<int>& imgDst, int Draw_CelPix_W, int Draw_CelPix_H,
	int WinCel_X, int WinCel_Y,
	double ValueRange,
	const double* qSrcCellHistogram)
{
	if (ValueRange < MINIMUM_DOUBLE_EPS_C) ValueRange = 1.0;
	ValueRange /= 256.0;
	
	int i_bin;
	int tc_r, tc_g, tc_b;

	int oW, oH;
	oW = Draw_CelPix_W * WinCel_W;
	oH = Draw_CelPix_H * WinCel_H;

	int xa, ya, xb, yb, rx, ry, dx, dy;
	rx = (int)(Draw_CelPix_W * 0.400);
	ry = (int)(Draw_CelPix_H * 0.400);
	xa = Draw_CelPix_W * WinCel_X + Draw_CelPix_W / 2;
	ya = Draw_CelPix_H * WinCel_Y + Draw_CelPix_H / 2;
	double ori;

	for ( i_bin = 0; i_bin < Hist_BinAmount; ++i_bin )
	{
		tc_g = CMyMath::TranslateNumber_Round(qSrcCellHistogram[i_bin] / ValueRange, (int)0);
		if (tc_g > 0)
		{
			tc_r = tc_g;
			tc_b = 0;
			tc_g = 0;
			if (tc_r > 255) tc_r = 255;
		}
		else
		{
			tc_r = 0;
			tc_b = -tc_g;
			tc_g = 0;
			if (tc_r > 255) tc_b = 255;
		}

		ori = pHistogramConfig->GetBinMiddleValue(i_bin);
		ori -= PI/2;

		dx = CMyMath::TranslateNumber_Round(rx * cos(ori), (int)0);
		dy = CMyMath::TranslateNumber_Round(ry * sin(ori), (int)0);

		const int* p_tc = CExternalTools::GetIntArrayRGB(tc_r, tc_g, tc_b);

		xb = xa + dx;
		yb = ya + dy;
		xb = (xb<0 ? 0 : (xb>=oW ? oW-1 : xb));
		yb = (yb<0 ? 0 : (yb>=oH ? oH-1 : yb));
		imgDst.draw_line(xa, ya, xb, yb, p_tc);

		xb = xa - dx;
		yb = ya - dy;
		xb = (xb<0 ? 0 : (xb>=oW ? oW-1 : xb));
		yb = (yb<0 ? 0 : (yb>=oH ? oH-1 : yb));
		imgDst.draw_line(xa, ya, xb, yb, p_tc);
	}
}

void new_boost::CWindowGradient::DrawGradientImage(
	CImg<int>& imgDst, int Draw_CelPix_W, int Draw_CelPix_H,
	const double* qSrcData)
{
	int i_feature, i_bin = 0;
	int ix, iy;
	int oW, oH;
	double range, tt;

	oW = Draw_CelPix_W * WinCel_W;
	oH = Draw_CelPix_H * WinCel_H;

	CSimpleTypeArray<double> vl;
	vl.Resize(Hist_BinAmount);
	
	CMyNormalizer_L2_NORM MyNormalizer;
	CMyNormalizer* pMyNormalizer = &MyNormalizer;

	//int Draw_ZeroBase = 128;

	imgDst.assign(oW, oH, 1, 3);
	imgDst.fill(0);

	vl.Clear();
	vl.PushBack(qSrcData, FeatureDimension);

	//pMyNormalizer->Normalize(vl);
	//range = 0.15;

	range = 0.0;
	for ( i_feature = 0; i_feature < FeatureDimension; ++i_feature )
	{
		tt = abs(vl.pElement[i_feature]);
		if (range < tt)
			range = tt;
	}

	i_feature = 0;
	for ( iy = 0; iy < WinCel_H; ++iy ) for ( ix = 0; ix < WinCel_W; ++ix )
	{
		_DrawCell(imgDst, Draw_CelPix_W, Draw_CelPix_H, ix, iy, range, vl.pElement + i_feature);
		i_feature += Hist_BinAmount;
	}
}

